package com.jvup.common.basic;

import androidx.core.util.Supplier;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;

/**
 * 此类包含用于对对象进行操作的静态实用程序方法。这些实用程序包括null安全或null容忍的方法，这些方法用于计算对象的哈希码，返回对象的字符串以及比较两个对象。
 */
public class ObjectUtil {

    private ObjectUtil() {
        throw new AssertionError("ObjectUtil 不能实例化");
    }

    /**
     * 如果参数彼此相等，则返回true；否则返回false。因此，如果两个参数都为null，则返回true；如果正好一个参数为null，则返回false。否则，将使用第一个参数的equals方法确定相等性。
     * @param a 要对照比较的对象
     * @param b 要与a进行相等性比较的对象
     * @return
     */
    public static boolean equals(Object a, Object b) {
        return (a == b) || (a != null && a.equals(b));
    }

    /**
     * 如果参数彼此不相等，则返回true；否则返回false。因此，如果两个参数都为null，则返回false；如果正好一个参数为null，则返回true。否则，将使用第一个参数的equals方法确定不相等性。
     * @param a 要对照比较的对象
     * @param b 要与a进行不相等性比较的对象
     * @return
     */
    public static boolean notEquals(Object a, Object b) {
        return !equals(a, b);
    }

    /**
     * @see Objects#deepEquals(Object, Object)
     */
    public static boolean deepEquals(Object a, Object b) {
        return Objects.deepEquals(a, b);
    }

    /**
     * 返回非{@code null}参数的哈希码，返回{@code null}参数的0。
     *
     * @param o 处理的对象
     * @return 非{@code null}参数的哈希码，{@code null} 参数的哈希码为0
     * @see Object#hashCode
     */
    public static int hashCode(Object o) {
        return o != null ? o.hashCode() : 0;
    }

    /**
     * 为一系列输入值生成哈希码。就像将所有输入值都放入一个数组中一样生成哈希码，并通过调用{@link Arrays#hashCode(Object[])}对该数组进行哈希处理。
     *
     * <p>此方法对于在包含多个字段的对象上实现 {@link Object#hashCode()} 很有用。例如，如果一个对象具有三个字段 {@code x}, {@code y}, and {@code z}, 则可以编写：
     *
     * <blockquote><pre>
     * &#064;Override public int hashCode() {
     *     return Objects.hash(x, y, z);
     * }
     * </pre></blockquote>
     *
     * <b>警告：提供单个对象引用时，返回值不等于该对象引用的哈希码。</b>
     * 可以通过调用  {@link #hashCode(Object)} 来计算此值。
     *
     * @param values 要散列的值
     * @return 输入值序列的哈希值
     * @see Arrays#hashCode(Object[])
     * @see List#hashCode
     */
    public static int hash(Object... values) {
        return Arrays.hashCode(values);
    }
    /**
     * 返回针对非null参数调用 {@code toString} 以及针对 {@code null} 参数调用 {@code "null"} 的结果。
     * @param o 对象
     * @return 对非null参数调用 {@code toString} 的结果，对 {@code null} 参数调用 {@code "null"} 的结果
     * @see Object#toString
     * @see String#valueOf(Object)
     */
    public static String toString(Object o) {
        return String.valueOf(o);
    }

    /**
     * 如果第一个参数不是 {@code null} ，则返回在第一个参数上调用 {@code toString} 的结果，否则返回第二个参数。
     * @param o 对象
     * @param nullDefault 如果第一个参数为{@code null}，则返回的字符串
     * @return 如果第一个参数不是 {@code null} ，则返回在第一个参数上调用 {@code toString} 的结果，否则返回第二个参数。
     * @see Objects#toString(Object)
     */
    public static String toString(Object o, String nullDefault) {
        return (o != null) ? o.toString() : nullDefault;
    }

    /**
     * 如果参数相同，则返回0，否则返回 {@code c.compare(a, b)} 因此，如果两个参数都为{@code null}，则返回0
     * <p>请注意，如果参数之一为 {@code null}，则可能会或可能不会引发 {@code NullPointerException} ，
     * 具体取决于哪种排序策略（如果有），{@link Comparator Comparator} 选择为 {@code null} 值。
     *
     * @param <T> 被比较对象的类型
     * @param a 比较对象
     * @param b 要与 {@code a} 比较的对象
     * @param c 使用 {@code Comparator} 比较前两个参数
     * @return 如果参数相同，则为0，否则为 {@code c.compare(a, b)}
     * @see Comparable
     * @see Comparator
     */
    public static <T> int compare(T a, T b, Comparator<? super T> c) {
        return (a == b) ? 0 :  c.compare(a, b);
    }

    /**
     * 检查指定的对象引用是否不是 {@code null}。此方法主要设计用于在方法和构造函数中进行参数验证，如下所示：
     * <blockquote><pre>
     * public Foo(Bar bar) {
     *     this.bar = Objects.requireNonNull(bar);
     * }
     * </pre></blockquote>
     *
     * @param obj 用于检查无效性的对象引用
     * @param <T> 引用的类型
     * @return 如果 {@code obj}  不是 {@code null} 返回 {@code obj}
     * @throws NullPointerException 如果 {@code obj} 是 {@code null}
     */
    public static <T> T requireNonNull(T obj) {
        if (obj == null)
            throw new NullPointerException();
        return obj;
    }

    /**
     * 检查指定的对象引用是否不是 {@code null} ，如果是，则抛出自定义的 {@link NullPointerException} 。此方法主要用于在具有多个参数的方法和构造函数中进行参数验证，如下所示：
     * <blockquote><pre>
     * public Foo(Bar bar, Baz baz) {
     *     this.bar = Objects.requireNonNull(bar, "bar must not be null");
     *     this.baz = Objects.requireNonNull(baz, "baz must not be null");
     * }
     * </pre></blockquote>
     *
     * @param obj     用于检查无效性的对象引用
     * @param message 抛出 {@code NullPointerException} 时使用的详细消息
     * @param <T> 引用的类型
     * @return 如果 {@code obj} 不是  {@code null} 返回 {@code obj}
     * @throws NullPointerException 如果 {@code obj} 是 {@code null}
     */
    public static <T> T requireNonNull(T obj, String message) {
        if (obj == null)
            throw new NullPointerException(message);
        return obj;
    }

    /**
     * 检查指定的对象引用是否不是 {@code null} ，如果是，则抛出自定义的{@link NullPointerException} 。
     *
     * <p>与方法 {@link #requireNonNull(Object, String)} 不同，此方法允许将消息的创建推迟到进行空检查之后。
     * 尽管这在非null情况下可能会带来性能优势，但是在决定调用此方法时，应注意创建消息提供者的成本要比直接创建字符串消息的成本要低。
     *
     * @param obj     用于检查无效性的对象引用
     * @param messageSupplier 在引发 {@code NullPointerException} 时使用的详细消息的提供者
     * @param <T> 引用的类型
     * @return 如果 {@code obj} 不是 {@code null} {@code obj}
     * @throws NullPointerException 如果 {@code obj} 是 {@code null}
     * @since 1.8
     */
    public static <T> T requireNonNull(T obj, Supplier<String> messageSupplier) {
        if (obj == null)
            throw new NullPointerException(messageSupplier.get());
        return obj;
    }


    /**
     * 如果提供的引用为null，则返回true，否则返回false。
     * @param obj 要对照null进行检查的引用
     * @return 如果提供的引用为null，则为true，否则为false
     */
    public static boolean isNull(Object obj) {
        return obj == null;
    }

    /**
     * 如果提供的引用为非null，则返回true，否则返回false。
     * @param obj 要对照null进行检查的引用
     * @return 如果提供的引用为非null，则为true；否则为false
     */
    public static boolean nonNull(Object obj) {
        return obj != null;
    }

    /**
     * 如果 {@code obj} 不为 {@code null} 则返回  {@code obj}，否则返回  {@code def}
     * @param obj 引用对象
     * @param def 默认对象
     * @param <T> 引用类型
     * @return 如果 {@code obj} 不为 {@code null} 则返回  {@code obj}，否则返回  {@code def}
     */
    public static <T> T nonNull(T obj, T def) {
        return obj != null ? obj : def;
    }

}
